﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Linq;
using Core.FrameWork.Commons.ORM.DataManager;
using Core.FrameWork.Commons.ORM.Enums;
using Core.FrameWork.Commons.Hepler;
using System.Reflection;
using Core.FrameWork.Commons.ORM.Models;
using Microsoft.Extensions.Logging;
using Core.FrameWork.Commons.Loging;

namespace Core.Freamwork.Repository
{
    public class BaseDbContext : DbContext
    {
        #region 基础参数

        /// <summary>
        /// 数据库配置名称，可在子类指定不同的配置名称，用于访问不同的数据库
        /// </summary>
        protected string dbConfigName = "";

        /// <summary>
        /// 
        /// </summary>
        protected DbConnectionOptions dbConnectionOptions;

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public DatabaseFacade GetDatabase() => Database;

        #endregion
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dbConnectionOptions"></param>
        public BaseDbContext()
        {

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dbConnectionOptions"></param>
        public BaseDbContext(DbConnectionOptions dbConnectionOptions)
        {
            this.dbConnectionOptions = dbConnectionOptions;
        }
        /// <summary>
        /// 配置，初始化数据库引擎
        /// </summary>
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (dbConnectionOptions == null)
            {
                dbConnectionOptions = DBServerProvider.GeDbConnectionOptions();
            }
            string defaultSqlConnectionString = dbConnectionOptions.ConnectionString;

            DatabaseType dbType = dbConnectionOptions.DatabaseType;

            var loggerFactory = new LoggerFactory();
            loggerFactory.AddProvider(new EFCoreLoggerProvider());
            if (dbType == DatabaseType.SqlServer)
            {
                optionsBuilder.UseSqlServer(defaultSqlConnectionString).UseLoggerFactory(loggerFactory).EnableSensitiveDataLogging();
            }
            else if (dbType == DatabaseType.MySql)
            {
                optionsBuilder.UseMySql(defaultSqlConnectionString, new MySqlServerVersion(new Version(8, 0, 21))).UseLoggerFactory(loggerFactory).EnableSensitiveDataLogging();
            }
            else
            {
                throw new NotSupportedException("The database is not supported");
            }
            //使用查询跟踪行为
            optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);




            base.OnConfiguring(optionsBuilder);
        }
        /// <summary>
        /// 模型创建
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            MappingEntityTypes(modelBuilder);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="modelBuilder"></param>
        private void MappingEntityTypes(ModelBuilder modelBuilder)
        {
            var assemblies = RuntimeHelper.GetAllAssemblies();
            foreach (var assembly in assemblies)
            {
                var entityTypes = assembly.GetTypes()
                    .Where(type => !string.IsNullOrWhiteSpace(type.Namespace))
                    .Where(type => type.IsClass)
                    .Where(type => type.BaseType != null)
                    .Where(type => typeof(BaseEntity).IsAssignableFrom(type));

                foreach (var entityType in entityTypes)
                {
                    if (modelBuilder.Model.FindEntityType(entityType) != null || entityType.Name == "Entity" || entityType.Name == "BaseEntity" || entityType.Name == "BaseSecendEntity`1")
                        continue;
                    var table = entityType.GetCustomAttributes<TableAttribute>().FirstOrDefault();
                    modelBuilder.Model.AddEntityType(entityType).SetTableName(table.Name);

                    //var ientityTypes = modelBuilder.Model.FindEntityType(entityType);
                    //var attr = entityType.GetCustomAttributes<ShardingTableAttribute>().FirstOrDefault();
                    //if (attr != null && entityType != null)
                    //{
                    //    modelBuilder.Model.FindEntityType(entityType).SetTableName($"{entityType.Name}{attr.Splitter}{DateTime.Now.ToString(attr.Suffix)}");
                    //}

                    //modelBuilder.Entity<Entity>().HasQueryFilter(s=>s)

                    if (typeof(IDeleteAudited).IsAssignableFrom(entityType))
                    {
                        //modelBuilder.Entity<BaseEntity>().HasQueryFilter(m => ((IDeleteAudited)m).IsDelete == 0);
                    }
                    //if (IsMultiTenant)
                    //{
                    //    if (typeof(IMustHaveTenant).IsAssignableFrom(typeof(Entity)))
                    //    {
                    //        modelBuilder.Entity<Entity>().HasQueryFilter(m => ((IMustHaveTenant)m).TenantId == "");
                    //    }
                    //}
                }
            }
        }
 
    }
}
